﻿namespace TNet
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;

    public static class Tools
    {
        public static bool isExternalIPReliable;
        private static TNet.List<IPAddress> mAddresses;
        private static string mChecker;
        private static IPAddress mExternalAddress;
        private static TNet.List<NetworkInterface> mInterfaces;
        private static IPAddress mLocalAddress;
        private static OnResolvedIPs mOnResolve;
        private static Thread mResolveThread;

        public static bool DeleteFile(string fileName)
        {
            try
            {
                if (System.IO.File.Exists(fileName))
                {
                    System.IO.File.Delete(fileName);
                }
                return true;
            }
            catch (Exception)
            {
            }
            return false;
        }

        private static IPAddress GetExternalAddress()
        {
            if (mExternalAddress != null)
            {
                return mExternalAddress;
            }
            if (ResolveExternalIP(ipCheckerUrl))
            {
                return mExternalAddress;
            }
            if (ResolveExternalIP("http://icanhazip.com"))
            {
                return mExternalAddress;
            }
            if (ResolveExternalIP("http://bot.whatismyipaddress.com"))
            {
                return mExternalAddress;
            }
            if (ResolveExternalIP("http://ipinfo.io/ip"))
            {
                return mExternalAddress;
            }
            return localAddress;
        }

        public static string[] GetFiles(string directory)
        {
            try
            {
                if (!Directory.Exists(directory))
                {
                    return null;
                }
                return Directory.GetFiles(directory);
            }
            catch (Exception)
            {
            }
            return null;
        }

        public static string GetResponse(WebRequest request)
        {
            string str = string.Empty;
            try
            {
                Stream responseStream = request.GetResponse().GetResponseStream();
                byte[] buffer = new byte[0x800];
                while (true)
                {
                    int count = responseStream.Read(buffer, 0, buffer.Length);
                    if (count <= 0)
                    {
                        return str;
                    }
                    str = str + Encoding.ASCII.GetString(buffer, 0, count);
                }
            }
            catch (Exception)
            {
                return null;
            }
            return str;
        }

        public static string GetSubnet(IPAddress ip)
        {
            if (ip == null)
            {
                return null;
            }
            string str = ip.ToString();
            int length = str.LastIndexOf('.');
            if (length == -1)
            {
                return null;
            }
            return str.Substring(0, length);
        }

        public static bool IsValidAddress(IPAddress address)
        {
            if (address.AddressFamily != AddressFamily.InterNetwork)
            {
                return false;
            }
            if (address.Equals(IPAddress.Loopback))
            {
                return false;
            }
            if (address.Equals(IPAddress.None))
            {
                return false;
            }
            if (address.Equals(IPAddress.Any))
            {
                return false;
            }
            if (address.ToString().StartsWith("169."))
            {
                return false;
            }
            return true;
        }

        public static byte[] ReadFile(string fileName)
        {
            try
            {
                if (System.IO.File.Exists(fileName))
                {
                    return System.IO.File.ReadAllBytes(fileName);
                }
            }
            catch (Exception)
            {
            }
            return null;
        }

        public static IPAddress ResolveAddress(string address)
        {
            address = address.Trim();
            if (!string.IsNullOrEmpty(address))
            {
                IPAddress address2;
                if (address == "localhost")
                {
                    return IPAddress.Loopback;
                }
                if (IPAddress.TryParse(address, out address2))
                {
                    return address2;
                }
                try
                {
                    IPAddress[] hostAddresses = Dns.GetHostAddresses(address);
                    for (int i = 0; i < hostAddresses.Length; i++)
                    {
                        if (!IPAddress.IsLoopback(hostAddresses[i]))
                        {
                            return hostAddresses[i];
                        }
                    }
                }
                catch (Exception)
                {
                }
            }
            return null;
        }

        private static void ResolveDummyFunc(IPAddress a, IPAddress b)
        {
        }

        public static IPEndPoint ResolveEndPoint(string address)
        {
            int result = 0;
            char[] separator = new char[] { ':' };
            string[] strArray = address.Split(separator);
            if (strArray.Length > 1)
            {
                address = strArray[0];
                int.TryParse(strArray[1], out result);
            }
            IPAddress address2 = ResolveAddress(address);
            return ((address2 == null) ? null : new IPEndPoint(address2, result));
        }

        public static IPEndPoint ResolveEndPoint(string address, int port)
        {
            IPEndPoint point = ResolveEndPoint(address);
            if (point != null)
            {
                point.Port = port;
            }
            return point;
        }

        private static bool ResolveExternalIP(string url)
        {
            if (!string.IsNullOrEmpty(url))
            {
                try
                {
                    WebClient client = new WebClient();
                    string address = client.DownloadString(url).Trim();
                    char[] separator = new char[] { ':' };
                    string[] strArray = address.Split(separator);
                    if (strArray.Length >= 2)
                    {
                        char[] chArray2 = new char[] { '<' };
                        mExternalAddress = ResolveAddress(strArray[1].Trim().Split(chArray2)[0]);
                    }
                    else
                    {
                        mExternalAddress = ResolveAddress(address);
                    }
                    if (mExternalAddress != null)
                    {
                        isExternalIPReliable = true;
                        return true;
                    }
                }
                catch (Exception)
                {
                }
            }
            return false;
        }

        public static void ResolveIPs()
        {
            ResolveIPs(null);
        }

        public static void ResolveIPs(OnResolvedIPs del)
        {
            if (isExternalIPReliable)
            {
                if (del != null)
                {
                    del(localAddress, externalAddress);
                }
            }
            else
            {
                if (Tools.mOnResolve == null)
                {
                    Tools.mOnResolve = new OnResolvedIPs(Tools.ResolveDummyFunc);
                }
                OnResolvedIPs mOnResolve = Tools.mOnResolve;
                lock (mOnResolve)
                {
                    if (del != null)
                    {
                        Tools.mOnResolve = (OnResolvedIPs) Delegate.Combine(Tools.mOnResolve, del);
                    }
                    if (mResolveThread == null)
                    {
                        mResolveThread = new Thread(new ThreadStart(Tools.ResolveThread));
                        mResolveThread.Start();
                    }
                }
            }
        }

        private static void ResolveThread()
        {
            IPAddress localAddress = Tools.localAddress;
            IPAddress externalAddress = Tools.externalAddress;
            OnResolvedIPs mOnResolve = Tools.mOnResolve;
            lock (mOnResolve)
            {
                if (Tools.mOnResolve != null)
                {
                    Tools.mOnResolve(localAddress, externalAddress);
                }
                mResolveThread = null;
                Tools.mOnResolve = null;
            }
        }

        public static void Serialize(BinaryReader reader, out IPEndPoint ip)
        {
            byte[] address = reader.ReadBytes(reader.ReadByte());
            int port = reader.ReadUInt16();
            ip = new IPEndPoint(new IPAddress(address), port);
        }

        public static void Serialize(BinaryWriter writer, IPEndPoint ip)
        {
            byte[] addressBytes = ip.Address.GetAddressBytes();
            writer.Write((byte) addressBytes.Length);
            writer.Write(addressBytes);
            writer.Write((ushort) ip.Port);
        }

        public static bool WriteFile(string fileName, byte[] data)
        {
            if ((data == null) || (data.Length == 0))
            {
                return DeleteFile(fileName);
            }
            try
            {
                string directoryName = Path.GetDirectoryName(fileName);
                if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
                {
                    Directory.CreateDirectory(directoryName);
                }
                System.IO.File.WriteAllBytes(fileName, data);
                return true;
            }
            catch (Exception)
            {
            }
            return false;
        }

        public static IPAddress externalAddress
        {
            get
            {
                if (mExternalAddress == null)
                {
                    mExternalAddress = GetExternalAddress();
                }
                return ((mExternalAddress == null) ? localAddress : mExternalAddress);
            }
        }

        public static string ipCheckerUrl
        {
            get
            {
                return mChecker;
            }
            set
            {
                if (mChecker != value)
                {
                    mChecker = value;
                    mLocalAddress = null;
                    mExternalAddress = null;
                }
            }
        }

        public static IPAddress localAddress
        {
            get
            {
                if (mLocalAddress == null)
                {
                    mLocalAddress = IPAddress.Loopback;
                    if (localAddresses.size > 0)
                    {
                        mLocalAddress = mAddresses[0];
                        for (int i = 0; i < mAddresses.size; i++)
                        {
                            IPAddress address = mAddresses[i];
                            if (!address.ToString().StartsWith("25."))
                            {
                                mLocalAddress = address;
                                break;
                            }
                        }
                    }
                }
                return mLocalAddress;
            }
            set
            {
                mLocalAddress = value;
                if (value != null)
                {
                    TNet.List<IPAddress> localAddresses = Tools.localAddresses;
                    for (int i = 0; i < localAddresses.size; i++)
                    {
                        if (localAddresses[i] == value)
                        {
                            return;
                        }
                    }
                }
                Console.WriteLine("[TNet] " + value + " is not one of the local IP addresses. Strange things may happen.");
            }
        }

        public static TNet.List<IPAddress> localAddresses
        {
            get
            {
                if (mAddresses == null)
                {
                    mAddresses = new TNet.List<IPAddress>();
                    try
                    {
                        TNet.List<NetworkInterface> networkInterfaces = Tools.networkInterfaces;
                        int size = networkInterfaces.size;
                        while (size > 0)
                        {
                            NetworkInterface interface2 = networkInterfaces[--size];
                            if (interface2 != null)
                            {
                                IPInterfaceProperties iPProperties = interface2.GetIPProperties();
                                if (iPProperties != null)
                                {
                                    UnicastIPAddressInformationCollection unicastAddresses = iPProperties.UnicastAddresses;
                                    if (unicastAddresses != null)
                                    {
                                        IEnumerator<UnicastIPAddressInformation> enumerator = unicastAddresses.GetEnumerator();
                                        try
                                        {
                                            while (enumerator.MoveNext())
                                            {
                                                UnicastIPAddressInformation current = enumerator.Current;
                                                if (IsValidAddress(current.Address))
                                                {
                                                    mAddresses.Add(current.Address);
                                                }
                                            }
                                            continue;
                                        }
                                        finally
                                        {
                                            if (enumerator == null)
                                            {
                                            }
                                            enumerator.Dispose();
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                    string hostName = Dns.GetHostName();
                    if (!string.IsNullOrEmpty(hostName))
                    {
                        IPAddress[] hostAddresses = Dns.GetHostAddresses(hostName);
                        if (hostAddresses != null)
                        {
                            foreach (IPAddress address in hostAddresses)
                            {
                                if (IsValidAddress(address) && !mAddresses.Contains(address))
                                {
                                    mAddresses.Add(address);
                                }
                            }
                        }
                    }
                    if (mAddresses.size == 0)
                    {
                        mAddresses.Add(IPAddress.Loopback);
                    }
                }
                return mAddresses;
            }
        }

        public static TNet.List<NetworkInterface> networkInterfaces
        {
            get
            {
                if (mInterfaces == null)
                {
                    mInterfaces = new TNet.List<NetworkInterface>();
                    foreach (NetworkInterface interface2 in NetworkInterface.GetAllNetworkInterfaces())
                    {
                        if (interface2.Supports(NetworkInterfaceComponent.IPv4) && ((interface2.OperationalStatus == OperationalStatus.Up) || (interface2.OperationalStatus == OperationalStatus.Unknown)))
                        {
                            mInterfaces.Add(interface2);
                        }
                    }
                }
                return mInterfaces;
            }
        }

        public static int randomPort
        {
            get
            {
                return (0x2710 + ((int) (DateTime.UtcNow.Ticks % 0xc350L)));
            }
        }

        public delegate void OnResolvedIPs(IPAddress local, IPAddress ext);
    }
}

